home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / viewkit / VCal / DayView.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  27.1 KB  |  1,214 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include <stdio.h>
  18. #include <time.h>
  19. #include <sys/time.h>
  20. #include "DayView.h"
  21. #include "VCal.h"
  22. #include "Info.h"
  23. #include "Entry.h"
  24. #include "EntryDialog.h"
  25. #include "Utils.h"
  26. #include "Preferences.h"
  27.  
  28. #include <Vk/VkScroll.h>
  29. #include <Vk/VkResource.h>
  30. #include <Vk/VkSubMenu.h>
  31. #include <Vk/VkRepeatButton.h>
  32. #include <Vk/VkMenu.h>
  33. #include <Vk/VkMenuBar.h>
  34. #include <Vk/VkMenuItem.h>
  35. #include <Vk/VkPopupMenu.h>
  36. #include <Vk/VkQuestionDialog.h>
  37. #include <Vk/VkHelpPane.h>
  38.  
  39. #include <Xm/Form.h>
  40. #include <Xm/Label.h>
  41. #include <Xm/ToggleBG.h>
  42. #include <Xm/RowColumn.h>
  43. #include <Xm/PushBG.h>
  44.  
  45. static Arg args[10];
  46. static int count;
  47.  
  48. void
  49. DayView::quit_menu(Widget, XtPointer client_data, XtPointer)
  50. {
  51.   DayView *obj = (DayView *) client_data;
  52.  
  53.   obj->doQuit();
  54. }
  55.  
  56. void
  57. DayView::restricted_menu(Widget w, XtPointer client_data, XtPointer)
  58. {
  59.   DayView *obj = (DayView *) client_data;
  60.  
  61.   obj->restrictedChanged(XmToggleButtonGadgetGetState(w));
  62. }
  63.  
  64. void
  65. DayView::day_select(Widget, XtPointer client_data, XEvent *event)
  66. {
  67.   DayView *obj = (DayView *) client_data;
  68.  
  69.   if (event->xbutton.button == 1) {
  70.     obj->displayToday();
  71.   }
  72. }
  73.  
  74. void
  75. DayView::weekday_menu(Widget, XtPointer client_data, XtPointer)
  76. {
  77.   VkCallbackStruct *cb = (VkCallbackStruct *) client_data;
  78.   DayView *obj = (DayView *) cb->obj;
  79.   int weekday = (int) cb->client_data;
  80.  
  81.   obj->selectWeekday(weekday);
  82. }
  83.  
  84. void
  85. DayView::entry_stub(Widget w, XtPointer client_data, XtPointer call_data)
  86. {
  87.   DayView *obj = (DayView *) client_data;
  88.   TimeEntryCallback *cb = (TimeEntryCallback *) call_data;
  89.  
  90.   obj->entryCallback(w, cb);
  91. }
  92.  
  93. void
  94. DayView::grid_stub(Widget, XtPointer client_data, XtPointer call_data)
  95. {
  96.   DayView *obj = (DayView *) client_data;
  97.   TimeGridCallback *cb = (TimeGridCallback *) call_data;
  98.  
  99.   obj->gridCallback(cb);
  100. }
  101.  
  102. void
  103. DayView::attributes_menu(Widget, XtPointer client_data, XtPointer)
  104. {
  105.   DayView *obj = (DayView *) client_data;
  106.  
  107.   obj->entryDialog(obj->menuEntry);
  108. }
  109.  
  110. void
  111. DayView::delete_menu(Widget, XtPointer client_data, XtPointer)
  112. {
  113.   DayView *obj = (DayView *) client_data;
  114.  
  115.   obj->deleteEntry(obj->menuEntry);
  116.   obj->scroll->reannotateScrollBar();
  117. }
  118.  
  119. Boolean
  120. DayView::reset_state(XtPointer client_data)
  121. {
  122.   DayView *obj = (DayView *) client_data;
  123.  
  124.   obj->owner->selectDay(obj->_day, obj->_month, obj->_year);
  125.   return True;
  126. }
  127.  
  128. void
  129. DayView::save_text(Widget, XtPointer client_data, XtPointer)
  130. {
  131.   DayView *obj = (DayView *) client_data;
  132.   
  133.   obj->owner->saveAsTextMenu(True, obj, obj->_day, obj->_month, obj->_year);
  134. }
  135.  
  136. void
  137. DayView::display_overview(Widget, XtPointer client_data, XtPointer)
  138. {
  139.   DayView *obj = (DayView *) client_data;
  140.   
  141.   obj->owner->displayWeekOverview();
  142. }
  143.  
  144. void
  145. DayView::entry_attributes(Widget, XtPointer client_data, XtPointer)
  146. {
  147.   DayView *obj = (DayView *) client_data;
  148.   
  149.   obj->entryAttributesMenu();
  150. }
  151.  
  152. void
  153. DayView::entry_delete(Widget, XtPointer client_data, XtPointer)
  154. {
  155.   DayView *obj = (DayView *) client_data;
  156.   
  157.   obj->entryDeleteMenu();
  158. }
  159.  
  160. /**********************************************************************/
  161.  
  162. void
  163. DayView::selectDate(int d, int m, int y, MemoryInfo *i, RepeatingEntry *r)
  164. {
  165. //  if (_day != d || _month != m || _year != y) {
  166.     grid->reset();
  167.     eraseEntries();
  168.     _day = d;
  169.     _month = m;
  170.     _year = y;
  171.     updateHeader();
  172. // So that the header changes immediately, while we change each of the
  173. // fields...
  174.     XmUpdateDisplay(header);
  175.     _info = i;
  176.     _repeating = r;
  177.     initEntries();
  178.     displayEntries();
  179.     updateTime();
  180. //  }
  181. }
  182.  
  183. void
  184. DayView::unselect()
  185. {
  186.   grid->reset();
  187.   eraseEntries();
  188.   _day = _month = _year = 0;
  189.   _info = NULL;
  190.   _repeating = NULL;
  191. }
  192.  
  193. void
  194. DayView::entryChanged(EntryDialog *dialog)
  195. {
  196.   Entry *dentry, *entry;
  197.   VkQuestionDialog *d;
  198.  
  199.   dentry = dialog->entry();
  200.   entry = findDialogEntry(dialog);
  201.   if (d = (VkQuestionDialog *) entry->alarmInfo()->alarm) {
  202.     delete d;
  203.     entry->alarmInfo()->alarm = NULL;
  204.   }
  205.   if (entry != dentry) {
  206.     removeEntry(entry);
  207.     addEntry(dentry);
  208.     dentry->setData(entry->data());
  209.     notifyOwner(dentry, entry);
  210.     delete entry;
  211.   } else {
  212.     notifyOwner(dentry);
  213.   }
  214.   if (dentry->repeating() &&
  215.       !((RepeatingEntry *) dentry)->repeatApplies(_day, _month, _year)) {
  216.     scheduleResetState();
  217.   }
  218. }
  219.  
  220. int
  221. DayView::eraseEntry(Entry *entry)
  222. {
  223.   DayViewInfo *info;
  224.  
  225.   info = (DayViewInfo *) entry->data();
  226.   if (info) {
  227.     delete info->time;
  228.     if (info->dialog) {
  229.       delete info->dialog;
  230.     }
  231.     delete info;
  232.     entry->setData(NULL);
  233.     return 1;
  234.   } else {
  235.     return 0;
  236.   }
  237. }
  238.  
  239. void
  240. DayView::updateTime()
  241. {
  242.   struct timeval t;
  243.   struct tm *now;
  244.  
  245.   gettimeofday(&t, NULL);
  246.   now = localtime(&t.tv_sec);
  247.   if (_day != now->tm_mday ||
  248.       _month != now->tm_mon+1 ||
  249.       _year != now->tm_year+1900) {
  250.     _lastTime = -1;
  251.     grid->hideCurrentTime();
  252.   } else {
  253.     _lastTime = now->tm_hour*60+now->tm_min;
  254.     grid->showCurrentTime(_lastTime);
  255.   }
  256.   scroll->reannotateScrollBar();
  257. }
  258.  
  259. void
  260. DayView::scrollToCurrentTime()
  261. {
  262.   struct timeval t;
  263.   struct tm *now;
  264.  
  265.   gettimeofday(&t, NULL);
  266.   now = localtime(&t.tv_sec);
  267.   if (_day == now->tm_mday ||
  268.       _month == now->tm_mon+1 ||
  269.       _year == now->tm_year+1900) {
  270.     scrollToTime(now->tm_hour*60+now->tm_min);
  271.   }
  272. }
  273.  
  274. void
  275. DayView::scrollToBeginning()
  276. {
  277.   scroll->setScrollPos(0);
  278. }
  279.  
  280. void
  281. DayView::scrollToTime(int time)
  282. {
  283.   int start, length, value, maximum, clipv;
  284.   int timev, destv;
  285.  
  286.   start = grid->getStart();
  287.   length = grid->getLength();
  288.   if (time >= start && time < start+length) {
  289.     count = 0;
  290.     XtSetArg(args[count], XmNmaximum, &maximum);  count++;
  291.     XtSetArg(args[count], XmNvalue, &value);  count++;
  292.     XtSetArg(args[count], XmNsliderSize, &clipv);  count++;
  293.     XtGetValues(scroll->getScrollBar(), args, count);
  294.  
  295.     timev = ((time-start)*maximum)/length;
  296.     if (timev < value || timev >= value+clipv) {
  297.       destv = timev-clipv/2;
  298.       if (destv+clipv >= maximum) {
  299.     destv = maximum-clipv-1;
  300.       }
  301.       if (destv < 0) {
  302.     destv = 0;
  303.       }
  304.       scroll->setScrollPos(destv);
  305.     }
  306.   }
  307. }
  308.  
  309. /**********************************************************************/
  310.  
  311. Widget
  312. DayView::setUpInterface(Widget parent)
  313. {
  314.   fileMenu();
  315.   displayMenu();
  316.   entryMenu();
  317.   if (menu()->helpPane()) {
  318.     menu()->helpPane()->setItemSensitivities(False, True, False, False,
  319.                          False);
  320.   }
  321.  
  322.   entryPopup = new VkPopupMenu();
  323.   entryPopup->addLabel("entryPopup");
  324.   entryPopup->addSeparator();
  325.   entryPopup->addAction("entryMenuAttributes", DayView::attributes_menu,
  326.             (XtPointer) this);
  327.   entryPopup->addAction("entryMenuDelete", DayView::delete_menu,
  328.             (XtPointer) this);
  329.   entryPopup->build(parent);
  330.   repeatingEntryPopup = new VkPopupMenu();
  331.   repeatingEntryPopup->addLabel("repeatingEntryPopup");
  332.   repeatingEntryPopup->addSeparator();
  333.   repeatingEntryPopup->addAction("repeatingEntryMenuAttributes",
  334.                  DayView::attributes_menu,
  335.                  (XtPointer) this);
  336.   repeatingEntryPopup->addAction("repeatingEntryMenuDelete",
  337.                  DayView::delete_menu,
  338.                  (XtPointer) this);
  339.   repeatingEntryPopup->build(parent);
  340.   count = 0;
  341.   XtSetArg(args[count], XmNpopupEnabled, False);  count++;
  342.   XtSetValues(entryPopup->baseWidget(), args, count);
  343.   XtSetValues(repeatingEntryPopup->baseWidget(), args, count);
  344.  
  345.   count = 0;
  346.   form = XmCreateForm(parent, "dayViewForm", args, count);
  347.  
  348.   scroll = new VkScroll("scroll", form);
  349.   VkAddCallbackMethod(VkScroll::scrollCallback, scroll, this,
  350.               DayView::scrollProc, NULL);
  351.   scroll->setAnnotations();
  352.  
  353.   dayPrev = new VkRepeatButton("dayPrev", form, RB_arrowButtonGadget);
  354.   count = 0;
  355.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  356.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  357.   XtSetValues(dayPrev->baseWidget(), args, count);
  358.   dayPrev->show();
  359.   VkAddCallbackMethod(VkRepeatButton::buttonCallback, dayPrev, this,
  360.               DayView::doDayPrev, NULL);
  361.  
  362.   dayNext = new VkRepeatButton("dayNext", form, RB_arrowButtonGadget);
  363.  
  364.   count = 0;
  365.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  366.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  367.   XtSetValues(dayNext->baseWidget(), args, count);
  368.   dayNext->show();
  369.   VkAddCallbackMethod(VkRepeatButton::buttonCallback, dayNext, this,
  370.               DayView::doDayNext, NULL);
  371.  
  372.   count = 0;
  373.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  374.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  375.   XtSetArg(args[count], XmNleftWidget, dayPrev->baseWidget());  count++;
  376.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_WIDGET);  count++;
  377.   XtSetArg(args[count], XmNrightWidget, dayNext->baseWidget());  count++;
  378.   XtSetArg(args[count], XmNbottomAttachment,
  379.        XmATTACH_OPPOSITE_WIDGET);  count++;
  380.   XtSetArg(args[count], XmNbottomWidget, dayPrev->baseWidget());  count++;
  381.   header = XmCreateLabel(form, "header", args, count);
  382.   XtManageChild(header);
  383.   XtAddEventHandler(header, ButtonPressMask, False,
  384.             (XtEventHandler) DayView::day_select,
  385.             (XtPointer) this);
  386.  
  387.   count = 0;
  388.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  389.   XtSetArg(args[count], XmNtopWidget, header);  count++;
  390.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  391.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  392.   XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
  393.   XtSetValues(scroll->baseWidget(), args, count);
  394.  
  395.   if (restricted) {
  396.     grid = new TimeGrid("timeGrid", scroll->getClip(), True,
  397.             timeInterval, subdivisions,
  398.             restrictStart, restrictEnd-restrictStart);
  399.   } else {
  400.     grid = new TimeGrid("timeGrid", scroll->getClip());
  401.   }
  402.   grid->setCallback(DayView::grid_stub, (XtPointer) this);
  403.   count = 0;
  404.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_NONE);  count++;
  405.   XtSetArg(args[count], XmNbottomAttachment, XmATTACH_NONE);  count++;
  406.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  407.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  408.   XtSetValues(grid->baseWidget(), args, count);
  409.   scroll->setChild(grid->baseWidget());
  410.   grid->show();
  411.  
  412.   XtManageChild(form);
  413.   return form;
  414. }
  415.  
  416. void
  417. DayView::handleWmDeleteMessage()
  418. {
  419.   doQuit();
  420. }
  421.  
  422. void
  423. DayView::fileMenu()
  424. {
  425.   VkSubMenu* menu = addMenuPane("dayFileMenu");
  426.   VkMenuToggle *item;
  427.  
  428.   item = menu->addToggle("restrictedToggleMenuItem",
  429.              DayView::restricted_menu,
  430.              (XtPointer) this);
  431.   item->setVisualState(thePreferences->restricted());
  432.   menu->addSeparator();
  433.   menu->addAction("dayQuitMenuItem",
  434.           DayView::quit_menu,
  435.           (XtPointer) this);
  436. }
  437.  
  438. void
  439. DayView::displayMenu()
  440. {
  441.   VkSubMenu* menu = addMenuPane("displayMenu");
  442.   
  443.   weekdayMenu(menu);
  444.   menu->addAction("weekOverviewMenuItem",
  445.           DayView::display_overview,
  446.           (XtPointer) this);
  447.   menu->addAction("saveAsTextMenuItem",
  448.           DayView::save_text,
  449.           (XtPointer) this);
  450. }
  451.  
  452. void
  453. DayView::entryMenu()
  454. {
  455.   VkSubMenu* menu = addMenuPane("entryMenu");
  456.   
  457.   entryAttrItem = menu->addAction("entryItemAttributes",
  458.                   DayView::entry_attributes,
  459.                   (XtPointer) this);
  460.   entryDeleteItem = menu->addAction("entryItemDelete",
  461.                     DayView::entry_delete,
  462.                     (XtPointer) this);
  463.   entryDeleteEverywhereItem = menu->addAction("entryItemDeleteEverywhere",
  464.                           DayView::entry_delete,
  465.                           (XtPointer) this);
  466.  
  467.   setMenuEntry(NULL);
  468. }
  469.  
  470. void
  471. DayView::updateHeader()
  472. {
  473.   int weekday;
  474.   XmString xs;
  475.   char str[256];
  476.  
  477.   weekday = computeWeekday(_day, _month, _year);
  478.   formatDate(weekday, _day, _month, _year, str);
  479.   xs = XmStringCreateSimple(str);
  480.   count = 0;
  481.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  482.   XtSetValues(header, args, count);
  483.   XmStringFree(xs);
  484. }
  485.  
  486. void
  487. DayView::initialExpose()
  488. {
  489.   count = 0;
  490.   XtSetArg(args[count], XmNincrement,
  491.        grid->getSlotHeight()*grid->getSubDiv());  count++;
  492.   XtSetValues(scroll->getScrollBar(), args, count);
  493.   updateTime();
  494. }
  495.  
  496. void
  497. DayView::restrictedChanged(Boolean r)
  498. {
  499.   if (restricted != r) {
  500.     theApplication->busy();
  501.     restricted = r;
  502.     hideEntries();
  503.     if (restricted) {
  504.       grid->changeDuration(restrictStart, restrictEnd-restrictStart);
  505.     } else {
  506.       grid->changeDuration(0, MINS_IN_DAY);
  507.     }
  508.     displayEntries();
  509.     updateTime();
  510.     scroll->recomputeScrollBar();
  511.     scrollToCurrentTime();
  512.     theApplication->notBusy();
  513.   }  
  514. }
  515.  
  516. void
  517. DayView::notifyOwner(Entry *entry, Entry *oldEntry)
  518. {
  519.   struct timeval t;
  520.   struct tm *now;
  521.  
  522.   gettimeofday(&t, NULL);
  523.   now = localtime(&t.tv_sec);
  524.   entry->setAlarmFired(entry->start() < now->tm_hour*60+now->tm_min,
  525.                ALL_NOTIFICATIONS);
  526.   owner->dayViewChanged(this, entry, oldEntry);
  527.   setMenuEntry(lastMenuEntry);
  528. }
  529.  
  530. void
  531. DayView::scrollProc(Widget, XtPointer, XtPointer call_data)
  532. {
  533.   VkScrollCallback *cb = (VkScrollCallback *) call_data;
  534.  
  535.   switch (cb->reason) {
  536.   case VS_initialExpose:
  537.     initialExpose();
  538.     break;
  539.   case VS_resize:
  540. // Make the grid reconfigure first
  541.     grid->reconfig();
  542.     displayEntries();
  543.     break;
  544.   case VS_troughPixmap:
  545.     drawTrough(cb);
  546.     break;
  547.   case VS_none:
  548.   default:
  549.     break;
  550.   }
  551. }
  552.  
  553. void
  554. DayView::drawTrough(VkScrollCallback *cb)
  555. {
  556.   XGCValues gcv;
  557.   Entry *entry;
  558.   RepeatingEntry *rentry;
  559.   Pixel fg;
  560.   int start, length, h;
  561.  
  562.   if (troughGC == NULL) {
  563.     count = 0;
  564.     XtSetArg(args[count], XmNforeground, &fg);  count++;
  565.     XtGetValues(header, args, count);
  566.     gcv.function = GXcopy;
  567.     gcv.foreground = fg;
  568.     gcv.background = owner->annotateColor();
  569.     gcv.stipple = owner->getTile();
  570.     gcv.fill_style = FillOpaqueStippled;
  571.     troughGC = XtGetGC(form,
  572.                GCFunction | GCForeground | GCBackground |
  573.                GCStipple | GCFillStyle,
  574.                &gcv);
  575.   }
  576.   if (timeGC == NULL && header) {
  577.     count = 0;
  578.     XtSetArg(args[count], XmNforeground, &fg);  count++;
  579.     XtGetValues(header, args, count);
  580.     gcv.function = GXcopy;
  581.     gcv.foreground = fg;
  582.     timeGC = XtGetGC(form,
  583.              GCFunction | GCForeground,
  584.              &gcv);
  585.   }
  586.  
  587.   if (_repeating) {
  588.     rentry = _repeating;
  589.     while (rentry->next()) {
  590.       rentry = rentry->next();
  591.       if (rentry->repeatApplies(_day, _month, _year)) {
  592.     annotateEntry(rentry, cb->width, cb->height, cb->pixmap);
  593.       }
  594.     }
  595.   }
  596.   if (_info) {
  597.     _info->rewind();
  598.     while (entry = _info->nextEntry()) {
  599.       annotateEntry(entry, cb->width, cb->height, cb->pixmap);
  600.     }
  601.   }
  602.   if (timeGC && _lastTime > -1) {
  603.     start = grid->getStart();
  604.     length = grid->getLength();
  605.     if (_lastTime >= start && _lastTime < start+length) {
  606.       h = ((_lastTime-start)*cb->height)/length;
  607.       if (h > 3) {
  608.     h -= 1;
  609.       }
  610.       XFillRectangle(XtDisplay(_baseWidget), cb->pixmap, timeGC,
  611.              0, h, cb->width, 1);
  612.     }
  613.   }
  614. }
  615.  
  616. void
  617. DayView::annotateEntry(Entry *entry, int width, int height, Pixmap pixmap)
  618. {
  619.   DayViewInfo *info;
  620.   Position y;
  621.   Dimension height2;
  622.   int h;
  623.  
  624.   info = (DayViewInfo *) entry->data();
  625.   if (info && XtIsManaged(info->time->baseWidget())) {
  626.     count = 0;
  627.     XtSetArg(args[count], XmNy, &y);  count++;
  628.     XtSetArg(args[count], XmNheight, &height2);  count++;
  629.     XtGetValues(info->time->baseWidget(), args, count);
  630.     h = ((int) height2*height)/grid->getHeight();
  631.     if (h > 3) {
  632.       h -= 1;
  633.     }
  634.     XFillRectangle(XtDisplay(_baseWidget), pixmap, troughGC,
  635.            0, ((int) y*height)/grid->getHeight(),
  636.            width, h);
  637.   }
  638. }
  639.  
  640. void
  641. DayView::doDayPrev(Widget, XtPointer, XtPointer)
  642. {
  643.   if (_day > 1) {
  644.     owner->selectDay(_day-1, _month, _year);
  645.   } else if (_month > 1) {
  646.     owner->selectDay(NumberOfDays(_month-1, _year), _month-1, _year);
  647.   } else {
  648.     owner->selectDay(NumberOfDays(12, _year), 12, _year-1);
  649.   }
  650. }
  651.  
  652. void
  653. DayView::doDayNext(Widget, XtPointer, XtPointer)
  654. {
  655.   if (_day < NumberOfDays(_month, _year)) {
  656.     owner->selectDay(_day+1, _month, _year);
  657.   } else if (_month < 12) {
  658.     owner->selectDay(1, _month+1, _year);
  659.   } else {
  660.     owner->selectDay(1, 1, _year+1);
  661.   }
  662. }
  663.  
  664. void
  665. DayView::displayToday()
  666. {
  667.   owner->selectToday();
  668.   scrollToCurrentTime();
  669. }
  670.  
  671. void
  672. DayView::weekdayMenu(VkMenu *parent)
  673. {
  674.   int each;
  675.   VkCallbackStruct *callbackStructs;
  676.   VkSubMenu *menu = parent->addSubmenu("weekdayMenu");
  677.  
  678.   callbackStructs = new VkCallbackStruct[DAYS_IN_WEEK];    // memory leak
  679.   for (each=0; each<DAYS_IN_WEEK; each++) {
  680.     callbackStructs[each].obj = this;
  681.     callbackStructs[each].client_data = (void *) (each+1);
  682.     menu->addAction(weekdayString(each+1), DayView::weekday_menu,
  683.             (XtPointer) &callbackStructs[each]);
  684.   }
  685. }
  686.  
  687. void
  688. DayView::selectWeekday(int day)
  689. {
  690.   int each, num, delta, wday;
  691.  
  692.   wday = computeWeekday(_day, _month, _year);
  693.   if (day == wday) {
  694.     return;
  695.   } else if (day > wday) {
  696.     delta = 1;
  697.     num = day-wday;
  698.   } else {
  699.     delta = -1;
  700.     num = wday - day;
  701.   }
  702.   for (each=0; each<num; each++) {
  703.     _day = _day+delta;
  704.     if (!_day) {
  705.       if (_month > 1) {
  706.     _month--;
  707.     _day = NumberOfDays(_month, _year);
  708.       } else {
  709.     _year--;
  710.     _month = 12;
  711.     _day = NumberOfDays(_month, _year);
  712.       }
  713.     } else if (_day > NumberOfDays(_month, _year)) {
  714.       _day = 1;
  715.       if (_month < 12) {
  716.     _month++;
  717.       } else {
  718.     _year++;
  719.     _month = 1;
  720.       }
  721.     }
  722.   }
  723.   owner->selectDay(_day, _month, _year);
  724. }
  725.  
  726. void
  727. DayView::initEntries()
  728. {
  729.   Entry *entry;
  730.   RepeatingEntry *rentry;
  731.  
  732.   if (_repeating) {
  733.     rentry = _repeating;
  734.     while (rentry->next()) {
  735.       rentry = rentry->next();
  736.       if (rentry->repeatApplies(_day, _month, _year)) {
  737.     initEntry(rentry);
  738.       }
  739.     }
  740.   }
  741.   if (_info) {
  742.     _info->rewind();
  743.     while (entry = _info->nextEntry()) {
  744.       initEntry(entry);
  745.     }
  746.   }
  747. }
  748.  
  749. void
  750. DayView::displayEntries()
  751. {
  752.   Entry *entry;
  753.   RepeatingEntry *rentry;
  754.  
  755.   if (_repeating) {
  756.     rentry = _repeating;
  757.     while (rentry->next()) {
  758.       rentry = rentry->next();
  759.       if (rentry->repeatApplies(_day, _month, _year)) {
  760.     displayEntry(rentry);
  761.       }
  762.     }
  763.   }
  764.   if (_info) {
  765.     _info->rewind();
  766.     while (entry = _info->nextEntry()) {
  767.       displayEntry(entry);
  768.     }
  769.   }
  770.   scroll->reannotateScrollBar();
  771. }
  772.  
  773. void
  774. DayView::hideEntries()
  775. {
  776.   Entry *entry;
  777.   RepeatingEntry *rentry;
  778.  
  779.   if (_repeating) {
  780.     rentry = _repeating;
  781.     while (rentry->next()) {
  782.       rentry = rentry->next();
  783.       if (rentry->repeatApplies(_day, _month, _year)) {
  784.     hideEntry(rentry);
  785.       }
  786.     }
  787.   }
  788.   if (_info) {
  789.     _info->rewind();
  790.     while (entry = _info->nextEntry()) {
  791.       hideEntry(entry);
  792.     }
  793.   }
  794.   scroll->reannotateScrollBar();
  795. }
  796.  
  797. void
  798. DayView::eraseEntries()
  799. {
  800.   Entry *entry;
  801.   RepeatingEntry *rentry;
  802.  
  803.   if (_repeating) {
  804.     rentry = _repeating;
  805.     while (rentry->next()) {
  806.       rentry = rentry->next();
  807. // So we erase repeating entries that no longer apply
  808. //      if (rentry->repeatApplies(_day, _month, _year)) {
  809.     eraseEntry(rentry);
  810. //      }
  811.     }
  812.   }
  813.   if (_info) {
  814.     _info->rewind();
  815.     while (entry = _info->nextEntry()) {
  816.       eraseEntry(entry);
  817.     }
  818.   }
  819. }
  820.  
  821. void
  822. DayView::initEntry(Entry *entry)
  823. {
  824.   DayViewInfo *info;
  825.  
  826.   info = new DayViewInfo;
  827.   info->dialog = NULL;
  828.   info->time = new TimeEntry("timeEntry", grid);
  829.   info->time->setCallback(DayView::entry_stub, (XtPointer) this);
  830.   entry->setData(info);
  831. }
  832.  
  833. void
  834. DayView::displayEntry(Entry *entry)
  835. {
  836.   DayViewInfo *info;
  837.  
  838.   info = (DayViewInfo *) entry->data();
  839.   info->time->setText(entry->text());
  840.   if (info->time->setTimeInterval(entry->start(), entry->length())) {
  841.     info->time->show();
  842.   }
  843. }
  844.  
  845. void
  846. DayView::hideEntry(Entry *entry)
  847. {
  848.   DayViewInfo *info;
  849.  
  850.   info = (DayViewInfo *) entry->data();
  851.   info->time->hide();
  852. }
  853.  
  854. void
  855. DayView::entryCallback(Widget w, TimeEntryCallback *cb)
  856. {
  857.   switch (cb->reason) {
  858.   case TE_textChanged:
  859.   case TE_timeChanged:
  860.     entryModified(findEntry(w), cb->reason);
  861.     break;
  862.   case TE_postMenu:
  863.     if (menuEntry = findEntry(w)) {
  864.       if (menuEntry->repeating()) {
  865.     XmMenuPosition(repeatingEntryPopup->baseWidget(), &cb->event->xbutton);
  866.     XtManageChild(repeatingEntryPopup->baseWidget());
  867.       } else {
  868.     XmMenuPosition(entryPopup->baseWidget(), &cb->event->xbutton);
  869.     XtManageChild(entryPopup->baseWidget());
  870.       }
  871.     }
  872.     break;
  873.   case TE_deselect:
  874.     if (cb->obj == lastMenuEntry) {
  875.       setMenuEntry(NULL);
  876.     }
  877.     grid->reset();
  878.     break;
  879.   case TE_selected:
  880.     setMenuEntry(cb->obj);
  881.   case TE_none:
  882.     break;
  883.   }
  884. }
  885.  
  886. Entry *
  887. DayView::findEntry(Widget w)
  888. {
  889.   DayViewInfo *info;
  890.   Entry *entry;
  891.   RepeatingEntry *rentry;
  892.  
  893.   if (_repeating) {
  894.     rentry = _repeating;
  895.     while (rentry->next()) {
  896.       rentry = rentry->next();
  897. // In case we modify entry attr so that the entry doesn't apply anymore
  898. //      if (rentry->repeatApplies(_day, _month, _year)) {
  899.     info = (DayViewInfo *) rentry->data();
  900.     if (info && info->time->baseWidget() == w) {
  901.       return rentry;
  902.     }
  903. //      }
  904.     }
  905.   }
  906.   if (_info) {
  907.     _info->rewind();
  908.     while (entry = _info->nextEntry()) {
  909.       info = (DayViewInfo *) entry->data();
  910.       if (info->time->baseWidget() == w) {
  911.     return entry;
  912.       }
  913.     }
  914.   }
  915.   return NULL;
  916. }
  917.  
  918. void
  919. DayView::entryModified(Entry *entry, TimeEntryReason reason)
  920. {
  921.   DayViewInfo *info;
  922.   char *str;
  923.  
  924.   info = (DayViewInfo *) entry->data();
  925.   if (reason == TE_timeChanged) {
  926.     entry->setTime(info->time->start(), info->time->length());
  927.   }
  928.   if (reason == TE_textChanged || reason == TE_timeChanged) {
  929.     str = info->time->getText();
  930.     entry->setText(str);
  931.     if (strlen(str)) {
  932.       notifyOwner(entry);
  933.     } else if (reason == TE_textChanged) {
  934.       deleteEntry(entry);
  935.     }
  936.     XtFree(str);
  937.   }
  938.   scroll->reannotateScrollBar();
  939. }
  940.  
  941. void
  942. DayView::deleteEntry(Entry *entry)
  943. {
  944.   DayViewInfo *info;
  945.   VkQuestionDialog *dialog;
  946.  
  947.   info = (DayViewInfo *) entry->data();
  948.   removeEntry(entry);
  949.   if (info->dialog) {
  950.     delete info->dialog;
  951.   }
  952.   delete info->time;
  953.   delete info;
  954.   if (dialog = (VkQuestionDialog *) entry->alarmInfo()->alarm) {
  955.     delete dialog;
  956.     entry->alarmInfo()->alarm = NULL;
  957.   }
  958.   notifyOwner(entry);
  959.   delete entry;
  960. }
  961.  
  962. void
  963. DayView::doQuit()
  964. {
  965.   grid->reset();
  966.   eraseEntries();
  967.   _day = _month = _year = 0;
  968.   owner->deleteDayView(this);
  969. }
  970.  
  971. void
  972. DayView::gridCallback(TimeGridCallback *cb)
  973. {
  974.   Entry *entry;
  975.   int start, last;
  976.  
  977.   switch (cb->reason) {
  978.   case TG_requestNew:
  979.     start = timeSlotSnap*(cb->value/timeSlotSnap);
  980.     if (restricted) {
  981.       last = restrictEnd;
  982.     } else {
  983.       last = MINS_IN_DAY;
  984.     }
  985.     if (start+defaultLength > last) {
  986.       start = last-defaultLength;
  987.     }
  988.     entry = createEntry(start, defaultLength);
  989.     displayEntry(entry);
  990.     selectEntry(entry, True);
  991.     scroll->reannotateScrollBar();
  992.     break;
  993.   case TG_deselect:
  994.     grid->reset();
  995.     setMenuEntry(NULL);
  996.     break;
  997.   case TG_none:
  998.     break;
  999.   }
  1000. }
  1001.  
  1002. Entry *
  1003. DayView::createEntry(int start, int length)
  1004. {
  1005.   Entry *entry;
  1006.  
  1007.   entry = new Entry();
  1008.   entry->setDate(_day, _month, _year);
  1009.   entry->setTime(start, length);
  1010.   entry->setNotifyPopup(thePreferences->notifyPopup());
  1011.   entry->setNotifyBell(thePreferences->notifyBell());
  1012.   entry->setNotifyMail(thePreferences->notifyMail());
  1013.   entry->setNotifyCommand(thePreferences->notifyCommand());
  1014.   entry->setAlarmAdvance(thePreferences->advanceWarning());
  1015.   entry->setAnnotate(thePreferences->annotateDay());
  1016.   addEntry(entry);
  1017.   initEntry(entry);
  1018.   notifyOwner(entry);
  1019.   return entry;
  1020. }
  1021.  
  1022. void
  1023. DayView::selectEntry(Entry *entry, Boolean makeModified)
  1024. {
  1025.   DayViewInfo *info;
  1026.  
  1027.   info = (DayViewInfo *) entry->data();
  1028.   info->time->select(makeModified);
  1029. }
  1030.  
  1031. void
  1032. DayView::entryDialog(Entry *entry)
  1033. {
  1034.   DayViewInfo *info;
  1035.  
  1036.   info = (DayViewInfo *) entry->data();
  1037.   if (info->dialog) {
  1038.     info->dialog->show();
  1039.   } else {
  1040.     theApplication->busy();
  1041.     info->dialog = new EntryDialog(entry, this, "entryDialog");
  1042.     info->dialog->post(NULL, NULL, NULL, NULL, NULL, "entryAttrDialog");
  1043.     theApplication->notBusy();
  1044.   }
  1045. }
  1046.  
  1047. Entry *
  1048. DayView::findDialogEntry(EntryDialog *dialog)
  1049. {
  1050.   Entry *entry;
  1051.   RepeatingEntry *rentry;
  1052.   DayViewInfo *info;
  1053.  
  1054.   if (_repeating) {
  1055.     rentry = _repeating;
  1056.     while (rentry->next()) {
  1057.       rentry = rentry->next();
  1058. // In case we modify entry attr so that the entry doesn't apply anymore
  1059. //      if (rentry->repeatApplies(_day, _month, _year)) {
  1060.     info = (DayViewInfo *) rentry->data();
  1061.     if (info && info->dialog == dialog) {
  1062.       return rentry;
  1063.     }
  1064. //      }
  1065.     }
  1066.   }
  1067.   if (_info) {
  1068.     _info->rewind();
  1069.     while (entry = _info->nextEntry()) {
  1070.       info = (DayViewInfo *) entry->data();
  1071.       if (info->dialog == dialog) {
  1072.     return entry;
  1073.       }
  1074.     }
  1075.   }
  1076.   return NULL;
  1077. }
  1078.  
  1079. void
  1080. DayView::removeEntry(Entry *entry)
  1081. {
  1082.   if (entry->repeating()) {
  1083.     owner->removeRepeatingEntry((RepeatingEntry *) entry);
  1084.   } else {
  1085.     _info->removeEntry(entry);
  1086.   }
  1087. }
  1088.  
  1089. void
  1090. DayView::addEntry(Entry *entry)
  1091. {
  1092.   struct timeval t;
  1093.   struct tm *now;
  1094.  
  1095.   gettimeofday(&t, NULL);
  1096.   now = localtime(&t.tv_sec);
  1097.   entry->setAlarmFired(entry->start() < now->tm_hour*60+now->tm_min,
  1098.                ALL_NOTIFICATIONS);
  1099.   if (entry->repeating()) {
  1100.     gettimeofday(&t, NULL);
  1101.     now = localtime(&t.tv_sec);
  1102.     owner->addRepeatingEntry((RepeatingEntry *) entry);
  1103.   } else {
  1104.     _info->addEntry(entry);
  1105.   }
  1106. }
  1107.  
  1108. void
  1109. DayView::scheduleResetState()
  1110. {
  1111.   XtAppAddWorkProc(theApplication->appContext(),
  1112.            DayView::reset_state, (XtPointer) this);
  1113. }
  1114.  
  1115. void
  1116. DayView::setMenuEntry(TimeEntry *entry)
  1117. {
  1118.   Entry *e;
  1119.  
  1120.   lastMenuEntry = entry;
  1121.   if (lastMenuEntry &&
  1122.       (e = findEntry(entry->baseWidget()))) {
  1123.     entryAttrItem->activate();
  1124.     if (e->repeating()) {
  1125.       entryDeleteItem->hide();
  1126.       entryDeleteEverywhereItem->show();
  1127.       entryDeleteEverywhereItem->activate();
  1128.     } else {
  1129.       entryDeleteEverywhereItem->hide();
  1130.       entryDeleteItem->show();
  1131.       entryDeleteItem->activate();
  1132.     }
  1133.   } else {
  1134.     entryAttrItem->deactivate();
  1135.     entryDeleteEverywhereItem->hide();
  1136.     entryDeleteItem->show();
  1137.     entryDeleteItem->deactivate();
  1138.   }
  1139. }
  1140.  
  1141. void
  1142. DayView::entryAttributesMenu()
  1143. {
  1144.   Entry *e;
  1145.  
  1146.   if (lastMenuEntry &&
  1147.       (e = findEntry(lastMenuEntry->baseWidget()))) {
  1148.     entryDialog(e);
  1149.   }
  1150. }
  1151.  
  1152. void
  1153. DayView::entryDeleteMenu()
  1154. {
  1155.   Entry *e;
  1156.  
  1157.   if (lastMenuEntry &&
  1158.       (e = findEntry(lastMenuEntry->baseWidget()))) {
  1159.     deleteEntry(e);
  1160.     scroll->reannotateScrollBar();
  1161.   }
  1162. }
  1163.  
  1164. /**********************************************************************/
  1165.  
  1166. DayView::DayView( VCal *o, const char *docName)
  1167. : VkWindow(docName)
  1168. {
  1169.   owner = o;
  1170.  
  1171.   numSlots = 0;
  1172.   _day = _month = _year = 0;
  1173.   _lastTime = 0;
  1174.   _info = NULL;
  1175.   _repeating = NULL;
  1176.   timeInterval = thePreferences->gridLength();
  1177.   subdivisions = thePreferences->apptSubdiv();
  1178.   timeSlotSnap = thePreferences->snapInterval();
  1179.   restricted = thePreferences->restricted();
  1180.   restrictStart = 60*thePreferences->restrictStart();
  1181.   restrictEnd = 60*thePreferences->restrictStop();
  1182.   defaultLength = thePreferences->apptLength();
  1183.  
  1184.   troughGC = NULL;
  1185.   timeGC = NULL;
  1186.   dayPrev = NULL;
  1187.   header = NULL;
  1188.   entryPopup = NULL;
  1189.   repeatingEntryPopup = NULL;
  1190.   lastMenuEntry = NULL;
  1191. }
  1192.  
  1193. DayView::~DayView()
  1194. {
  1195.   if (entryPopup) {
  1196.     delete entryPopup;
  1197.   }
  1198.   if (repeatingEntryPopup) {
  1199.     delete repeatingEntryPopup;
  1200.   }
  1201.   if (troughGC) {
  1202.     XtReleaseGC(form, troughGC);
  1203.   }
  1204.   if (timeGC) {
  1205.     XtReleaseGC(form, timeGC);
  1206.   }
  1207. }
  1208.  
  1209. const char *
  1210. DayView::className()
  1211. {
  1212.   return "DayView";
  1213. }
  1214.